// Copyright Epic Games, Inc. All Rights Reserved.

#include "LyraHeroComponent.h"
#include "Components/GameFrameworkComponentDelegates.h"
#include "Logging/MessageLog.h"
#include "LyraLogChannels.h"
#include "EnhancedInputSubsystems.h"
#include "Player/LyraPlayerController.h"
#include "Player/LyraPlayerState.h"
#include "Player/LyraLocalPlayer.h"
#include "Character/LyraPawnExtensionComponent.h"
#include "Character/LyraPawnData.h"
#include "Character/LyraCharacter.h"
#include "AbilitySystem/LyraAbilitySystemComponent.h"
#include "Input/LyraInputConfig.h"
#include "Input/LyraInputComponent.h"
#include "Camera/LyraCameraComponent.h"
#include "LyraGameplayTags.h"
#include "Components/GameFrameworkComponentManager.h"
#include "PlayerMappableInputConfig.h"
#include "Camera/LyraCameraMode.h"
#include "UserSettings/EnhancedInputUserSettings.h"
#include "InputMappingContext.h"

#include UE_INLINE_GENERATED_CPP_BY_NAME(LyraHeroComponent)

#if WITH_EDITOR // 如果有编辑器
#include "Misc/UObjectToken.h"
#endif	// WITH_EDITOR

namespace LyraHero
{
	static const float LookYawRate = 300.0f; // 视角偏航速率
	static const float LookPitchRate = 165.0f; // 视角俯仰速率
};

const FName ULyraHeroComponent::NAME_BindInputsNow("BindInputsNow"); // 立即绑定输入名称
const FName ULyraHeroComponent::NAME_ActorFeatureName("Hero"); // Actor功能名称

/**
 * 构造函数
 */
ULyraHeroComponent::ULyraHeroComponent(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer) // 调用父类构造函数
{
	AbilityCameraMode = nullptr; // 能力相机模式
	bReadyToBindInputs = false; // 准备绑定输入
}

/**
 * 注册时调用
 */
void ULyraHeroComponent::OnRegister()
{
	Super::OnRegister(); // 调用父类方法

	if (!GetPawn<APawn>()) // 如果没有获取到Pawn
	{
		UE_LOG(LogLyra, Error, TEXT("[ULyraHeroComponent::OnRegister] This component has been added to a blueprint whose base class is not a Pawn. To use this component, it MUST be placed on a Pawn Blueprint.")); // 记录错误日志

#if WITH_EDITOR // 如果有编辑器
		if (GIsEditor) // 如果是编辑器
		{
			static const FText Message = NSLOCTEXT("LyraHeroComponent", "NotOnPawnError", "has been added to a blueprint whose base class is not a Pawn. To use this component, it MUST be placed on a Pawn Blueprint. This will cause a crash if you PIE!"); // 消息
			static const FName HeroMessageLogName = TEXT("LyraHeroComponent"); // 英雄消息日志名称
			
			FMessageLog(HeroMessageLogName).Error() // 消息日志错误
				->AddToken(FUObjectToken::Create(this, FText::FromString(GetNameSafe(this)))) // 添加对象令牌
				->AddToken(FTextToken::Create(Message)); // 添加文本令牌
				
			FMessageLog(HeroMessageLogName).Open(); // 打开消息日志
		}
#endif
	}
	else // 否则
	{
		// 尽早向初始化状态系统注册，这仅在这是游戏世界时有效
		RegisterInitStateFeature(); // 注册初始化状态功能
	}
}

/**
 * 检查是否可以改变初始化状态
 */
bool ULyraHeroComponent::CanChangeInitState(UGameFrameworkComponentManager* Manager, FGameplayTag CurrentState, FGameplayTag DesiredState) const
{
	check(Manager); // 检查管理器

	APawn* Pawn = GetPawn<APawn>(); // 获取Pawn

	if (!CurrentState.IsValid() && DesiredState == LyraGameplayTags::InitState_Spawned) // 如果当前状态无效且期望状态是已生成
	{
		// 只要我们有真实的Pawn，就允许我们转换
		if (Pawn) // 如果Pawn存在
		{
			return true; // 返回true
		}
	}
	else if (CurrentState == LyraGameplayTags::InitState_Spawned && DesiredState == LyraGameplayTags::InitState_DataAvailable) // 如果当前状态是已生成且期望状态是数据可用
	{
		// 需要玩家状态。
		if (!GetPlayerState<ALyraPlayerState>()) // 如果没有获取到玩家状态
		{
			return false; // 返回false
		}

		// 如果我们是权威或自主的，我们需要等待一个控制器，该控制器已注册对玩家状态的所有权。
		if (Pawn->GetLocalRole() != ROLE_SimulatedProxy) // 如果本地角色不是模拟代理
		{
			AController* Controller = GetController<AController>(); // 获取控制器

			const bool bHasControllerPairedWithPS = (Controller != nullptr) &&  // 是否有与玩家状态配对的控制器
				(Controller->PlayerState != nullptr) &&  // 控制器玩家状态不为空
				(Controller->PlayerState->GetOwner() == Controller); // 控制器玩家状态的所有者是控制器

			if (!bHasControllerPairedWithPS) // 如果没有与玩家状态配对的控制器
			{
				return false; // 返回false
			}
		}

		const bool bIsLocallyControlled = Pawn->IsLocallyControlled(); // 是否本地控制
		const bool bIsBot = Pawn->IsBotControlled(); // 是否机器人控制

		if (bIsLocallyControlled && !bIsBot) // 如果本地控制且不是机器人
		{
			ALyraPlayerController* LyraPC = GetController<ALyraPlayerController>(); // 获取Lyra玩家控制器

			// 本地控制时需要输入组件和本地玩家。
			if (!Pawn->InputComponent || !LyraPC || !LyraPC->GetLocalPlayer()) // 如果没有输入组件或没有Lyra玩家控制器或没有本地玩家
			{
				return false; // 返回false
			}
		}

		return true; // 返回true
	}
	else if (CurrentState == LyraGameplayTags::InitState_DataAvailable && DesiredState == LyraGameplayTags::InitState_DataInitialized) // 如果当前状态是数据可用且期望状态是数据已初始化
	{
		// 等待玩家状态和扩展组件
		ALyraPlayerState* LyraPS = GetPlayerState<ALyraPlayerState>(); // 获取Lyra玩家状态

		return LyraPS && Manager->HasFeatureReachedInitState(Pawn, ULyraPawnExtensionComponent::NAME_ActorFeatureName, LyraGameplayTags::InitState_DataInitialized); // 返回是否有玩家状态且功能已达到初始化状态
	}
	else if (CurrentState == LyraGameplayTags::InitState_DataInitialized && DesiredState == LyraGameplayTags::InitState_GameplayReady) // 如果当前状态是数据已初始化且期望状态是游戏准备就绪
	{
		// TODO 添加能力初始化检查？
		return true; // 返回true
	}

	return false; // 返回false
}

/**
 * 处理改变初始化状态
 */
void ULyraHeroComponent::HandleChangeInitState(UGameFrameworkComponentManager* Manager, FGameplayTag CurrentState, FGameplayTag DesiredState)
{
	if (CurrentState == LyraGameplayTags::InitState_DataAvailable && DesiredState == LyraGameplayTags::InitState_DataInitialized) // 如果当前状态是数据可用且期望状态是数据已初始化
	{
		APawn* Pawn = GetPawn<APawn>(); // 获取Pawn
		ALyraPlayerState* LyraPS = GetPlayerState<ALyraPlayerState>(); // 获取Lyra玩家状态
		if (!ensure(Pawn && LyraPS)) // 确保Pawn和Lyra玩家状态存在
		{
			return; // 返回
		}

		const ULyraPawnData* PawnData = nullptr; // Pawn数据

		if (ULyraPawnExtensionComponent* PawnExtComp = ULyraPawnExtensionComponent::FindPawnExtensionComponent(Pawn)) // 如果找到Pawn扩展组件
		{
			PawnData = PawnExtComp->GetPawnData<ULyraPawnData>(); // 获取Pawn数据

			// 玩家状态保存此玩家的持久数据（在死亡和多个Pawn之间持续存在的状态）。
			// 能力系统组件和属性集位于玩家状态上。
			PawnExtComp->InitializeAbilitySystem(LyraPS->GetLyraAbilitySystemComponent(), LyraPS); // 初始化能力系统
		}

		if (ALyraPlayerController* LyraPC = GetController<ALyraPlayerController>()) // 如果获取到Lyra玩家控制器
		{
			if (Pawn->InputComponent != nullptr) // 如果输入组件不为空
			{
				InitializePlayerInput(Pawn->InputComponent); // 初始化玩家输入
			}
		}

		// 为所有Pawn挂钩委托，以防我们稍后观察
		if (PawnData) // 如果Pawn数据存在
		{
			if (ULyraCameraComponent* CameraComponent = ULyraCameraComponent::FindCameraComponent(Pawn)) // 如果找到相机组件
			{
				CameraComponent->DetermineCameraModeDelegate.BindUObject(this, &ThisClass::DetermineCameraMode); // 绑定确定相机模式委托
			}
		}
	}
}

/**
 * Actor初始化状态改变时调用
 */
void ULyraHeroComponent::OnActorInitStateChanged(const FActorInitStateChangedParams& Params)
{
	if (Params.FeatureName == ULyraPawnExtensionComponent::NAME_ActorFeatureName) // 如果功能名称是Pawn扩展组件功能名称
	{
		if (Params.FeatureState == LyraGameplayTags::InitState_DataInitialized) // 如果功能状态是数据已初始化
		{
			// 如果扩展组件说所有其他组件都已初始化，尝试进入下一个状态
			CheckDefaultInitialization(); // 检查默认初始化
		}
	}
}

/**
 * 检查默认初始化
 */
void ULyraHeroComponent::CheckDefaultInitialization()
{
	static const TArray<FGameplayTag> StateChain = { LyraGameplayTags::InitState_Spawned, LyraGameplayTags::InitState_DataAvailable, LyraGameplayTags::InitState_DataInitialized, LyraGameplayTags::InitState_GameplayReady }; // 状态链

	// 这将尝试从已生成（仅在BeginPlay中设置）通过数据初始化阶段进展，直到达到游戏准备就绪
	ContinueInitStateChain(StateChain); // 继续初始化状态链
}

/**
 * 开始游戏时调用
 */
void ULyraHeroComponent::BeginPlay()
{
	Super::BeginPlay(); // 调用父类方法

	// 监听所有功能的变化
	BindOnActorInitStateChanged(NAME_None, FGameplayTag(), false); // 绑定Actor初始化状态改变

	// 通知我们已完成生成，然后尝试其余的默认初始化
	ensure(TryToChangeInitState(LyraGameplayTags::InitState_Spawned)); // 确保尝试改变初始化状态为已生成
	CheckDefaultInitialization(); // 检查默认初始化
}

/**
 * 结束游戏时调用
 */
void ULyraHeroComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
	UnregisterInitStateFeature(); // 取消注册初始化状态功能

	Super::EndPlay(EndPlayReason); // 调用父类方法
}

/**
 * 初始化玩家输入
 */
void ULyraHeroComponent::InitializePlayerInput(UInputComponent* PlayerInputComponent)
{
	check(PlayerInputComponent); // 检查玩家输入组件

	const APawn* Pawn = GetPawn<APawn>(); // 获取Pawn
	if (!Pawn) // 如果Pawn不存在
	{
		return; // 返回
	}

	const APlayerController* PC = GetController<APlayerController>(); // 获取玩家控制器
	check(PC); // 检查玩家控制器

	const ULyraLocalPlayer* LP = Cast<ULyraLocalPlayer>(PC->GetLocalPlayer()); // 获取Lyra本地玩家
	check(LP); // 检查Lyra本地玩家

	UEnhancedInputLocalPlayerSubsystem* Subsystem = LP->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(); // 获取增强输入本地玩家子系统
	check(Subsystem); // 检查子系统

	Subsystem->ClearAllMappings(); // 清除所有映射

	if (const ULyraPawnExtensionComponent* PawnExtComp = ULyraPawnExtensionComponent::FindPawnExtensionComponent(Pawn)) // 如果找到Pawn扩展组件
	{
		if (const ULyraPawnData* PawnData = PawnExtComp->GetPawnData<ULyraPawnData>()) // 如果获取到Pawn数据
		{
			if (const ULyraInputConfig* InputConfig = PawnData->InputConfig) // 如果输入配置存在
			{
				for (const FInputMappingContextAndPriority& Mapping : DefaultInputMappings) // 遍历默认输入映射
				{
					if (UInputMappingContext* IMC = Mapping.InputMapping.LoadSynchronous()) // 如果输入映射上下文同步加载成功
					{
						if (Mapping.bRegisterWithSettings) // 如果使用设置注册
						{
							if (UEnhancedInputUserSettings* Settings = Subsystem->GetUserSettings()) // 如果获取到用户设置
							{
								Settings->RegisterInputMappingContext(IMC); // 注册输入映射上下文
							}
							
							FModifyContextOptions Options = {}; // 修改上下文选项
							Options.bIgnoreAllPressedKeysUntilRelease = false; // 忽略所有按下的键直到释放
							// 实际将配置添加到本地玩家							
							Subsystem->AddMappingContext(IMC, Mapping.Priority, Options); // 添加映射上下文
						}
					}
				}

				// Lyra输入组件有一些额外的功能将游戏标签映射到输入动作。
				// 如果你想要这个功能但仍然想改变你的输入组件类，使其成为ULyraInputComponent的子类或相应地修改此组件。
				ULyraInputComponent* LyraIC = Cast<ULyraInputComponent>(PlayerInputComponent); // 转换为Lyra输入组件
				if (ensureMsgf(LyraIC, TEXT("Unexpected Input Component class! The Gameplay Abilities will not be bound to their inputs. Change the input component to ULyraInputComponent or a subclass of it."))) // 确保是Lyra输入组件
				{
					// 添加玩家可能设置的键映射
					LyraIC->AddInputMappings(InputConfig, Subsystem); // 添加输入映射

					// 这是我们实际将输入动作绑定到游戏标签的地方，这意味着游戏能力蓝图将直接由这些输入动作的Triggered事件触发。
					TArray<uint32> BindHandles; // 绑定句柄
					LyraIC->BindAbilityActions(InputConfig, this, &ThisClass::Input_AbilityInputTagPressed, &ThisClass::Input_AbilityInputTagReleased, /*out*/ BindHandles); // 绑定能力动作

					LyraIC->BindNativeAction(InputConfig, LyraGameplayTags::InputTag_Move, ETriggerEvent::Triggered, this, &ThisClass::Input_Move, /*bLogIfNotFound=*/ false); // 绑定本机动作：移动
					LyraIC->BindNativeAction(InputConfig, LyraGameplayTags::InputTag_Look_Mouse, ETriggerEvent::Triggered, this, &ThisClass::Input_LookMouse, /*bLogIfNotFound=*/ false); // 绑定本机动作：鼠标视角
					LyraIC->BindNativeAction(InputConfig, LyraGameplayTags::InputTag_Look_Stick, ETriggerEvent::Triggered, this, &ThisClass::Input_LookStick, /*bLogIfNotFound=*/ false); // 绑定本机动作：摇杆视角
					LyraIC->BindNativeAction(InputConfig, LyraGameplayTags::InputTag_Crouch, ETriggerEvent::Triggered, this, &ThisClass::Input_Crouch, /*bLogIfNotFound=*/ false); // 绑定本机动作：下蹲
					LyraIC->BindNativeAction(InputConfig, LyraGameplayTags::InputTag_AutoRun, ETriggerEvent::Triggered, this, &ThisClass::Input_AutoRun, /*bLogIfNotFound=*/ false); // 绑定本机动作：自动奔跑
				}
			}
		}
	}

	if (ensure(!bReadyToBindInputs)) // 确保未准备绑定输入
	{
		bReadyToBindInputs = true; // 设置准备绑定输入为true
	}
 
	UGameFrameworkComponentManager::SendGameFrameworkComponentExtensionEvent(const_cast<APlayerController*>(PC), NAME_BindInputsNow); // 发送游戏框架组件扩展事件：玩家控制器
	UGameFrameworkComponentManager::SendGameFrameworkComponentExtensionEvent(const_cast<APawn*>(Pawn), NAME_BindInputsNow); // 发送游戏框架组件扩展事件：Pawn
}

/**
 * 添加额外输入配置
 */
void ULyraHeroComponent::AddAdditionalInputConfig(const ULyraInputConfig* InputConfig)
{
	TArray<uint32> BindHandles; // 绑定句柄

	const APawn* Pawn = GetPawn<APawn>(); // 获取Pawn
	if (!Pawn) // 如果Pawn不存在
	{
		return; // 返回
	}
	
	const APlayerController* PC = GetController<APlayerController>(); // 获取玩家控制器
	check(PC); // 检查玩家控制器

	const ULocalPlayer* LP = PC->GetLocalPlayer(); // 获取本地玩家
	check(LP); // 检查本地玩家

	UEnhancedInputLocalPlayerSubsystem* Subsystem = LP->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(); // 获取增强输入本地玩家子系统
	check(Subsystem); // 检查子系统

	if (const ULyraPawnExtensionComponent* PawnExtComp = ULyraPawnExtensionComponent::FindPawnExtensionComponent(Pawn)) // 如果找到Pawn扩展组件
	{
		ULyraInputComponent* LyraIC = Pawn->FindComponentByClass<ULyraInputComponent>(); // 查找Lyra输入组件
		if (ensureMsgf(LyraIC, TEXT("Unexpected Input Component class! The Gameplay Abilities will not be bound to their inputs. Change the input component to ULyraInputComponent or a subclass of it."))) // 确保是Lyra输入组件
		{
			LyraIC->BindAbilityActions(InputConfig, this, &ThisClass::Input_AbilityInputTagPressed, &ThisClass::Input_AbilityInputTagReleased, /*out*/ BindHandles); // 绑定能力动作
		}
	}
}

/**
 * 移除额外输入配置
 */
void ULyraHeroComponent::RemoveAdditionalInputConfig(const ULyraInputConfig* InputConfig)
{
	//@TODO: 实现我！
}

/**
 * 检查是否准备绑定输入
 */
bool ULyraHeroComponent::IsReadyToBindInputs() const
{
	return bReadyToBindInputs; // 返回准备绑定输入
}

/**
 * 输入：能力输入标签按下
 */
void ULyraHeroComponent::Input_AbilityInputTagPressed(FGameplayTag InputTag)
{
	if (const APawn* Pawn = GetPawn<APawn>()) // 如果获取到Pawn
	{
		if (const ULyraPawnExtensionComponent* PawnExtComp = ULyraPawnExtensionComponent::FindPawnExtensionComponent(Pawn)) // 如果找到Pawn扩展组件
		{
			if (ULyraAbilitySystemComponent* LyraASC = PawnExtComp->GetLyraAbilitySystemComponent()) // 如果获取到Lyra能力系统组件
			{
				LyraASC->AbilityInputTagPressed(InputTag); // 能力输入标签按下
			}
		}	
	}
}

/**
 * 输入：能力输入标签释放
 */
void ULyraHeroComponent::Input_AbilityInputTagReleased(FGameplayTag InputTag)
{
	const APawn* Pawn = GetPawn<APawn>(); // 获取Pawn
	if (!Pawn) // 如果Pawn不存在
	{
		return; // 返回
	}

	if (const ULyraPawnExtensionComponent* PawnExtComp = ULyraPawnExtensionComponent::FindPawnExtensionComponent(Pawn)) // 如果找到Pawn扩展组件
	{
		if (ULyraAbilitySystemComponent* LyraASC = PawnExtComp->GetLyraAbilitySystemComponent()) // 如果获取到Lyra能力系统组件
		{
			LyraASC->AbilityInputTagReleased(InputTag); // 能力输入标签释放
		}
	}
}

/**
 * 输入：移动
 */
void ULyraHeroComponent::Input_Move(const FInputActionValue& InputActionValue)
{
	APawn* Pawn = GetPawn<APawn>(); // 获取Pawn
	AController* Controller = Pawn ? Pawn->GetController() : nullptr; // 获取控制器

	// 如果玩家再次尝试移动，则取消自动奔跑
	if (ALyraPlayerController* LyraController = Cast<ALyraPlayerController>(Controller)) // 如果转换为Lyra玩家控制器
	{
		LyraController->SetIsAutoRunning(false); // 设置是否自动奔跑为false
	}
	
	if (Controller) // 如果控制器存在
	{
		const FVector2D Value = InputActionValue.Get<FVector2D>(); // 获取二维值
		const FRotator MovementRotation(0.0f, Controller->GetControlRotation().Yaw, 0.0f); // 移动旋转

		if (Value.X != 0.0f) // 如果X值不为0
		{
			const FVector MovementDirection = MovementRotation.RotateVector(FVector::RightVector); // 移动方向
			Pawn->AddMovementInput(MovementDirection, Value.X); // 添加移动输入
		}

		if (Value.Y != 0.0f) // 如果Y值不为0
		{
			const FVector MovementDirection = MovementRotation.RotateVector(FVector::ForwardVector); // 移动方向
			Pawn->AddMovementInput(MovementDirection, Value.Y); // 添加移动输入
		}
	}
}

/**
 * 输入：鼠标视角
 */
void ULyraHeroComponent::Input_LookMouse(const FInputActionValue& InputActionValue)
{
	APawn* Pawn = GetPawn<APawn>(); // 获取Pawn

	if (!Pawn) // 如果Pawn不存在
	{
		return; // 返回
	}
	
	const FVector2D Value = InputActionValue.Get<FVector2D>(); // 获取二维值

	if (Value.X != 0.0f) // 如果X值不为0
	{
		Pawn->AddControllerYawInput(Value.X); // 添加控制器偏航输入
	}

	if (Value.Y != 0.0f) // 如果Y值不为0
	{
		Pawn->AddControllerPitchInput(Value.Y); // 添加控制器俯仰输入
	}
}

/**
 * 输入：摇杆视角
 */
void ULyraHeroComponent::Input_LookStick(const FInputActionValue& InputActionValue)
{
	APawn* Pawn = GetPawn<APawn>(); // 获取Pawn

	if (!Pawn) // 如果Pawn不存在
	{
		return; // 返回
	}
	
	const FVector2D Value = InputActionValue.Get<FVector2D>(); // 获取二维值

	const UWorld* World = GetWorld(); // 获取世界
	check(World); // 检查世界

	if (Value.X != 0.0f) // 如果X值不为0
	{
		Pawn->AddControllerYawInput(Value.X * LyraHero::LookYawRate * World->GetDeltaSeconds()); // 添加控制器偏航输入
	}

	if (Value.Y != 0.0f) // 如果Y值不为0
	{
		Pawn->AddControllerPitchInput(Value.Y * LyraHero::LookPitchRate * World->GetDeltaSeconds()); // 添加控制器俯仰输入
	}
}

/**
 * 输入：下蹲
 */
void ULyraHeroComponent::Input_Crouch(const FInputActionValue& InputActionValue)
{
	if (ALyraCharacter* Character = GetPawn<ALyraCharacter>()) // 如果获取到Lyra角色
	{
		Character->ToggleCrouch(); // 切换下蹲
	}
}

/**
 * 输入：自动奔跑
 */
void ULyraHeroComponent::Input_AutoRun(const FInputActionValue& InputActionValue)
{
	if (APawn* Pawn = GetPawn<APawn>()) // 如果获取到Pawn
	{
		if (ALyraPlayerController* Controller = Cast<ALyraPlayerController>(Pawn->GetController())) // 如果转换为Lyra玩家控制器
		{
			// 切换自动奔跑
			Controller->SetIsAutoRunning(!Controller->GetIsAutoRunning()); // 设置是否自动奔跑
		}	
	}
}

/**
 * 确定相机模式
 */
TSubclassOf<ULyraCameraMode> ULyraHeroComponent::DetermineCameraMode() const
{
	if (AbilityCameraMode) // 如果能力相机模式存在
	{
		return AbilityCameraMode; // 返回能力相机模式
	}

	const APawn* Pawn = GetPawn<APawn>(); // 获取Pawn
	if (!Pawn) // 如果Pawn不存在
	{
		return nullptr; // 返回空
	}

	if (ULyraPawnExtensionComponent* PawnExtComp = ULyraPawnExtensionComponent::FindPawnExtensionComponent(Pawn)) // 如果找到Pawn扩展组件
	{
		if (const ULyraPawnData* PawnData = PawnExtComp->GetPawnData<ULyraPawnData>()) // 如果获取到Pawn数据
		{
			return PawnData->DefaultCameraMode; // 返回默认相机模式
		}
	}

	return nullptr; // 返回空
}

/**
 * 设置能力相机模式
 */
void ULyraHeroComponent::SetAbilityCameraMode(TSubclassOf<ULyraCameraMode> CameraMode, const FGameplayAbilitySpecHandle& OwningSpecHandle)
{
	if (CameraMode) // 如果相机模式存在
	{
		AbilityCameraMode = CameraMode; // 设置能力相机模式
		AbilityCameraModeOwningSpecHandle = OwningSpecHandle; // 设置能力相机模式拥有规范句柄
	}
}

/**
 * 清除能力相机模式
 */
void ULyraHeroComponent::ClearAbilityCameraMode(const FGameplayAbilitySpecHandle& OwningSpecHandle)
{
	if (AbilityCameraModeOwningSpecHandle == OwningSpecHandle) // 如果能力相机模式拥有规范句柄等于拥有规范句柄
	{
		AbilityCameraMode = nullptr; // 清空能力相机模式
		AbilityCameraModeOwningSpecHandle = FGameplayAbilitySpecHandle(); // 清空能力相机模式拥有规范句柄
	}
}